#ifndef _CONFIG_H
#define _CONFIG_H

#include <bits/stdc++.h>
#include "ejson.h"
#include <string>
#include <vector>

#if defined (__unix__) || defined (__APPLE__)
#include <cstring>
#define _strcmpi strcasecmp
#endif

namespace config
{
	using namespace EasyJson;
	using std::vector;

	//template<typename T>

	/* The key of json */
	#define HELP                      "help"
	#define TIP                       "tips"
	#define VALUE_H                   "value_h"
	#define VALUE_L                   "value"
	#define CHECKBOX                  "CheckBox"
  	#define ACTION                    "action"
	#define YEAR                      "year"
	#define MONTH                     "month"
	#define DAY                       "day"
	#define HOUR                      "hour"
	#define MINUTE                    "minute"
	#define SECOND                    "second"
	#define LISTVAL                    "list"
	#define CFGFILE                    "CfgFile"
	#define CFGVARFILE                 "SetupVarFile"
	#define BOOTORDERSHOW              "BootOrderShow"

	#define BOOTEX                     1
	#define SHOW                       2 

	#define EFIDP_MESSAGE_TYPE	0x03
	#define EFIDP_MSG_SATA		0x12
	#define EFIDP_MSG_NVME		0x17

	#define ManuFacBootVar      "ManufacturingBootOrder"
	#define PrimaryBootVar      "PrimaryBootOrder"
	#define ManuFacHELP         "Set the system Manufacturing boot order"
	#define PrimaryHELP         "Set the system Primary boot order"

	#define FIXVAR              "%*[^=]=%[^:]:%[^:]:%x:%s"
	
	#define BBS_OEM_HARDDISK      0x10
	#define BBS_OEM_HARDDISK1     0x11
	#define BBS_OEM_HARDDISK2     0x12
	#define BBS_OEM_HARDDISK3     0x13
	#define BBS_OEM_HARDDISK4     0x14
	#define BBS_OEM_HARDDISK5     0x15
	#define BBS_OEM_HARDDISK6     0x16
	#define BBS_OEM_HARDDISK7     0x17
	#define BBS_OEM_HARDDISK8     0x18

	#define BBS_OEM_CDROM         0x20
	#define BBS_OEM_CDROM1        0x21
	#define BBS_OEM_CDROM2        0x22
	#define BBS_OEM_CDROM3        0x23
	#define BBS_OEM_CDROM4        0x24
	#define BBS_OEM_CDROM5        0x25
	#define BBS_OEM_CDROM6        0x26

	#define BBS_OEM_USB_FLOPPY    0x30
	#define BBS_OEM_USB_FLOPPY1   0x31
	#define BBS_OEM_USB_FLOPPY2   0x32
	#define BBS_OEM_USB_FLOPPY3   0x33
	#define BBS_OEM_USB_FLOPPY4   0x34

	#define BBS_OEM_USB_KEY       0x40
	#define BBS_OEM_USB_KEY1      0x41
	#define BBS_OEM_USB_KEY2      0x42
	#define BBS_OEM_USB_KEY3      0x43
	#define BBS_OEM_USB_KEY4      0x44

	#define BBS_OEM_USB_HDD       0x50
	#define BBS_OEM_USB_HDD1      0x51
	#define BBS_OEM_USB_HDD2      0x52
	#define BBS_OEM_USB_HDD3      0x53
	#define BBS_OEM_USB_HDD4      0x54

	#define BBS_OEM_USB_CDROM     0x60
	#define BBS_OEM_USB_CDROM1    0x61
	#define BBS_OEM_USB_CDROM2    0x62
	#define BBS_OEM_USB_CDROM3    0x63
	#define BBS_OEM_USB_CDROM4    0x64

	#define BBS_OEM_NETWORK       0x70
	#define BBS_OEM_NETWORK1      0x71
	#define BBS_OEM_NETWORK2      0x72
	#define BBS_OEM_NETWORK3      0x73
	#define BBS_OEM_NETWORK4      0x74

	#define BBS_OEM_INTERNAL_FV   0x80
	#define BBS_OEM_INTERNAL_FV1  0x81
	#define BBS_OEM_INTERNAL_FV2  0x82
	#define BBS_OEM_INTERNAL_FV3  0x83
	#define BBS_OEM_INTERNAL_FV4  0x84

	#define BBS_OEM_M2    0x90
	#define BBS_OEM_M2_1  0x91
	#define BBS_OEM_M2_2  0x92
	#define BBS_OEM_M2_3  0x93
	#define BBS_OEM_M2_4  0x94

	#define BBS_OEM_PCIE_STORAGE   0xA0
	#define BBS_OEM_PCIE_STORAGE1  0xA1
	#define BBS_OEM_PCIE_STORAGE2  0xA2
	#define BBS_OEM_PCIE_STORAGE3  0xA3
	#define BBS_OEM_PCIE_STORAGE4  0xA4

	#define BBS_OEM_OTHER         0xF0

	enum ValueType
  	{
  		NUM    =    0,
		CHECK,
		STRING,
		DATE,
		TIME,
		LIST
	};

	struct Question
	{
		string name;
		uint16_t Id;
		uint64_t value;
	};

	struct VaribleInfo
	{
			string name;
			vector<uint64_t> valoption;
			//T value;
			uint16_t VaribleId;
			uint16_t FormId;
			uint64_t max;
			uint64_t min;
			string guid;
			int size;
			int offset;

			ValueType type;
			bool firstBoot;
			bool varFlag;
			bool bbootorder;
			bool CfgFlag;
			JSONObject obj;
			JSONArray CfgList;
			string defaultstr;
			uint64_t defaultval;
			uint64_t val;
			string str;
	};

	struct TreeInfo
	{
			int father;
			int child;
			VaribleInfo value;
	};

	struct BootVal
	{
		uint64_t NewVal;
		VaribleInfo VarInfo;
	};

	struct BootOrder
	{
		string name;
		uint32_t u32offset;
		uint8_t u8size;
		uint8_t au8value[16];
	};

	struct BootInfo
	{
		string CName;
		VARIABLE_PACK stBootOrder;
		string CDescription;
		uint16_t u16Index;
		uint16_t u16SataId;
		uint32_t u32NvmeId;
	};

	typedef struct {
		uint8_t type;
		uint8_t subtype;
		uint16_t length;
	}  EFIDP;

	typedef struct {
		EFIDP header;
		uint16_t	hba_port;
		uint16_t	port_multiplier_port;
		uint16_t	lun;
	}  EFIDP_SATA;

	typedef struct {
		EFIDP	header;
		uint32_t	namespace_id;
		uint8_t		ieee_eui_64[8];
	} EFIDP_NVME;
	
	class VarConfig
	{
			public:
				VarConfig(){TreeInfo temp = {0}; temp.child = 2; temp.father = 0; VarTree.push_back(temp);};
				int SetFirstBoot(int mode, string FirstBoot, map<int, vector<EFI_VARIABLE_PACK>> &variableMap);
				int BootDefault(int mode, map<int, vector<EFI_VARIABLE_PACK>> &variableMap);
				void BootModeParse(int mode, map<int, vector<EFI_VARIABLE_PACK>> &variableMap);
				void BootOrderParse(map<int, vector<EFI_VARIABLE_PACK>> &VarMap);
				int FixVar(string VarCfg, map<int, vector<EFI_VARIABLE_PACK>> &VarMap);
				void CreatFile(const string &outputFile, uint8_t u8Flag);
				void ParseCfgFile(void);
				void generateUEFIIFRDump(const string &outputFile, const vector<UEFI_IFR_STRING_PACK> &stringPackages,  const vector<UEFI_IFR_FORM_SET_PACK> &formSets, const string &buffer, const vector<string> &strings, map<int, vector<EFI_VARIABLE_PACK>> &VarMap, vector<string> inVarFile);
				int ParseConfig (const string &InputFile, map<int, vector<EFI_VARIABLE_PACK>> &VarMap);
				void CfgFIleInit(vector<string> inVarFile);
				int  InitSingleBootList(const string &InputFile);
				int IsInSingleList(uint8_t BootID);
			private:
				vector<uint8_t> conditionalStack;
				int BootOrderVaild(uint64_t NewVal, VaribleInfo VarInfo, vector<VARIABLE_PACK *> &VariblePackage);
				int FixBootOder (uint64_t NewVal, VaribleInfo VarInfo, vector<VARIABLE_PACK *> &VariblePackage);
				int ReplaceVar (VaribleInfo VarInfo, JSONObject *ConfigObj, vector<VARIABLE_PACK *> &VariblePackage);
				int DevicePathParse(uint8_t *pDevicePath, uint64_t len, BootInfo *pstBootInfo);
				uint8_t numberOfTabs;
				void FindFormTitle(uint32_t id,uint32_t Tid, vector<TreeInfo> &FormTree,  string &FormSetname, const vector<UEFI_IFR_STRING_PACK> &stringPackages, const vector<UEFI_IFR_FORM_SET_PACK> &formSets, const string &buffer, const vector<string> &strings, map<int, vector<EFI_VARIABLE_PACK>> &VarMap, vector<string> inVarFile);
				int SetFirstBootModify(string FirstBoot,VARIABLE_PACK *pstBootOrder);
				void IndentText(uint8_t reason)
				{
				    // Increment number of tabs
				    numberOfTabs++;

				    // Add to conditional stack
				    conditionalStack.push_back(reason);
				}
				std::map<uint8_t,std::string>  singlelist;
				bool bBootOrder = false;
				bool bShow = false;
				vector<BootVal> BootValTree;
				vector<TreeInfo> VarTree;
				void CreateJson (int index);
				void CfgFileInitial(int index);
				void CreateBootOrderJson (int index);
				int FindVar (int index, JSONObject *ConfigObj, map<int, vector<EFI_VARIABLE_PACK>> &VarMap);
	};
}

#endif

